import os
from math import sqrt
from characterStatsLog import CreateAllStatsFiles, EmptyDelta, STATS_SCHEMA
from codeGeneration import UE3_VAR_PREFIX
from appConst import CHARACTER_POSITION_RESPAWN, CHARACTER_POSITION_RUN, CHARACTER_POSITION_DRIVEN, CHARACTER_POSITION_FLOWN
UE3_VAR_PREFIX_LOWER = UE3_VAR_PREFIX.lower()
STATNAME_KILLS = 'kills'
STATNAME_DEATHS = 'deaths'
STATNAME_SUICIDES = 'suicides'
STATNAME_WARPOINTS = 'warpointsEarned'
STATNAME_PO_HACKED = 'primaryObjectivesHacked'
STATNAME_SO_HACKED = 'secondaryObjectivesHacked'
STATNAME_MCC_DESTROYED = 'mccsDestroyed'
STATNAME_MCC_SURGE = 'mccsSurged'
STATNAME_IC_DESTROYED = 'installationComponentsDestroyed'
STATNAME_DISTANCE_RUN = 'distanceRun'
STATNAME_DISTANCE_DRIVEN = 'distanceDriven'
STATNAME_DISTANCE_FLOWN = 'distanceFlown'
STATNAME_FAVO_WEAPON = 'favoriteWeapon'
STATNAME_LEAST_FAVO_WEAPON = 'leastFavoriteWeapon'
STATNAME_FAVO_VEHICLE = 'favoriteVehicle'
STATNAME_LEAST_FAVO_VEHICLE = 'leastFavoriteVehicle'
STATNAME_ASSIST_KILLS = 'assistKills'
STATNAME_ASSIST_KILLS_IN_VEHICLE = 'assistKillsInVehicle'
CLASSNAME_MCC = 'DustVehMCC'
CLASSNAME_IC = 'InstallationContent'
CLASSNAME_TURRET = 'TurretContent'
CLASSNAME_CHARACTER = 'CharacterContent'
FAVO_ITEM = 'favoriteItem'
NULL_ITEM = 0
LEAST_FAVO_ITEM = 'leastFavoriteItem'
IN_MATCH_SUFFIX = 'InMatch'
DAMAGE_BY_PERSON = 0
DAMAGE_BY_VEHICLE = 1
characterStats = [(STATNAME_KILLS, 'int'),
 (STATNAME_DEATHS, 'int'),
 (STATNAME_SUICIDES, 'int'),
 (STATNAME_WARPOINTS, 'int'),
 (STATNAME_PO_HACKED, 'int'),
 (STATNAME_SO_HACKED, 'int'),
 (STATNAME_MCC_DESTROYED, 'int'),
 (STATNAME_MCC_SURGE, 'int'),
 (STATNAME_IC_DESTROYED, 'int'),
 (STATNAME_DISTANCE_RUN, 'int'),
 (STATNAME_DISTANCE_DRIVEN, 'int'),
 (STATNAME_DISTANCE_FLOWN, 'int'),
 (STATNAME_FAVO_WEAPON, 'int'),
 (STATNAME_LEAST_FAVO_WEAPON, 'int'),
 (STATNAME_FAVO_VEHICLE, 'int'),
 (STATNAME_LEAST_FAVO_VEHICLE, 'int'),
 (STATNAME_ASSIST_KILLS, 'int'),
 (STATNAME_ASSIST_KILLS_IN_VEHICLE, 'int')]

def GetVar(event, attributeName):
    return event[attributeName]



def GenerateKillStatDelta(callingProcess, eventList):
    delta = EmptyDelta()
    for event in eventList:
        killerID = GetVar(event, 'killerID')
        victimID = GetVar(event, 'victimID')
        killerTypeID = GetVar(event, 'killerPawnTypeID')
        victimTypeID = GetVar(event, 'victimPawnTypeID')
        victimClassList = callingProcess.db.GetTypeByID(victimTypeID).GetClassNameList()
        if (CLASSNAME_CHARACTER not in victimClassList):
            continue
        if (killerID == victimID):
            delta[killerID][STATNAME_SUICIDES] += 1
        else:
            killerClassList = callingProcess.db.GetTypeByID(victimTypeID).GetClassNameList()
            if (CLASSNAME_CHARACTER in killerClassList):
                delta[killerID][STATNAME_KILLS] += 1
        delta[victimID][STATNAME_DEATHS] += 1

    return delta



def GenerateAssistKillStatDelta(callingProcess, eventList):
    delta = EmptyDelta()
    for event in eventList:
        instigatorID = event['instigatorID']
        typeID = event['damageType']
        if (typeID == DAMAGE_BY_PERSON):
            delta[instigatorID][STATNAME_ASSIST_KILLS] += 1
        else:
            if (typeID == DAMAGE_BY_VEHICLE):
                delta[instigatorID][STATNAME_ASSIST_KILLS_IN_VEHICLE] += 1

    return delta



def GenerateWarPointStatDelta(callingProcess, eventList):
    delta = EmptyDelta()
    for event in eventList:
        charID = GetVar(event, 'actorID')
        amount = GetVar(event, 'delta')
        if (amount <= 0):
            continue
        delta[charID][STATNAME_WARPOINTS] += amount

    return delta



def GenerateObjectiveHackStatDelta(callingProcess, eventList):
    delta = EmptyDelta()
    for event in eventList:
        if not GetVar(event, 'captured'):
            continue
        charID = GetVar(event, 'actorID')
        isPrimary = (0 == GetVar(event, 'objectiveType'))
        if isPrimary:
            delta[charID][STATNAME_PO_HACKED] += 1
        else:
            delta[charID][STATNAME_SO_HACKED] += 1

    return delta



def GenerateObjectDestructionStatDelta(callingProcess, eventList):
    delta = EmptyDelta()
    for event in eventList:
        charID = GetVar(event, 'actorID')
        typeID = GetVar(event, 'objectTypeID')
        try:
            typeObj = callingProcess.db.GetTypeByID(typeID)
        except KeyError, e:
            callingProcess.log.error('Got an ObjectDestruction event for nonexistent type %s!', typeID)
            continue
        classNameList = typeObj.GetClassNameList()
        if (CLASSNAME_MCC in classNameList):
            delta[charID][STATNAME_MCC_DESTROYED] += 1
        elif ((CLASSNAME_IC in classNameList) or (CLASSNAME_TURRET in classNameList)):
            delta[charID][STATNAME_IC_DESTROYED] += 1
        else:
            callingProcess.log.warning("ObjectDestruction event '%s' with classes '%s' wasn't processed for stats!", typeID, classNameList)

    return delta



def GenerateMCCSurgeStatDelta(callingProcess, eventList):
    delta = EmptyDelta()
    for event in eventList:
        charID = GetVar(event, 'actorID')
        delta[charID][STATNAME_MCC_SURGE] += 1

    return delta



def GenerateMatchWinStatDelta(callingProcess, eventList):
    return EmptyDelta()



def GenerateTeamSelectStatDelta(callingProcess, eventList):
    return EmptyDelta()



def CharPosEqual(a, b):
    if ((a['actorID'] == b['actorID']) and ((a['position_x'] == b['position_x']) and ((a['position_y'] == b['position_y']) and ((a['position_z'] == b['position_z']) and (a['vehicleTypeID'] == b['vehicleTypeID']))))):
        return True
    else:
        return False



def Distance(x1, y1, z1, x2, y2, z2):
    return sqrt(((((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2))) + ((z1 - z2) * (z1 - z2))))



def CharPosDistance(p1, p2):
    return Distance(p1['position_x'], p1['position_y'], p1['position_z'], p2['position_x'], p2['position_y'], p2['position_z'])


playerLastPos = {}

def ProcessCharacterPositionEvents(eventList):
    lastPos = {}
    for (k, v,) in playerLastPos.items():
        lastPos[k] = v

    uniqEvents = []
    for event in eventList:
        actorID = event['actorID']
        last = (lastPos[actorID] if (actorID in lastPos) else None)
        if ((last is None) or (not CharPosEqual(last, event))):
            uniqEvents.append(event)
            lastPos[actorID] = event

    eventList[:] = uniqEvents



def GenerateCharacterPositionStatDelta(callingProcess, eventList):
    delta = EmptyDelta()
    mapNames = {CHARACTER_POSITION_RUN: STATNAME_DISTANCE_RUN,
     CHARACTER_POSITION_DRIVEN: STATNAME_DISTANCE_DRIVEN,
     CHARACTER_POSITION_FLOWN: STATNAME_DISTANCE_FLOWN}
    for event in eventList:
        actorID = event['actorID']
        lastPos = (playerLastPos[actorID] if (actorID in playerLastPos) else None)
        vehicleTypeID = event['vehicleTypeID']
        notEqualLast = ((lastPos is not None) and (not CharPosEqual(lastPos, event)))
        if (notEqualLast and (vehicleTypeID != CHARACTER_POSITION_RESPAWN)):
            delta[actorID][mapNames[vehicleTypeID]] += CharPosDistance(lastPos, event)
        if ((lastPos is None) or notEqualLast):
            playerLastPos[actorID] = event

    for actorID in delta:
        delta[actorID][STATNAME_DISTANCE_RUN] /= 100.0
        delta[actorID][STATNAME_DISTANCE_DRIVEN] /= 100.0
        delta[actorID][STATNAME_DISTANCE_FLOWN] /= 100.0

    return delta


playerWeaponUsage = EmptyDelta()
playerWeaponTime = EmptyDelta()
playerVehicleUsage = EmptyDelta()
playerVehicleTime = EmptyDelta()
playerWeaponTimeInMatch = EmptyDelta()
playerVehicleTimeInMatch = EmptyDelta()

def GetFavoriteAndLeastFavoriteItems(actorID, playerItemTime):
    bFirstItem = True
    (favoriteItem, leastFavoriteItem,) = (NULL_ITEM, NULL_ITEM)
    for (item, itemTime,) in playerItemTime[actorID].iteritems():
        if bFirstItem:
            favoriteItem = leastFavoriteItem = item
            favoriteTime = leastFavoriteTime = itemTime
            bFirstItem = False
        elif (itemTime > favoriteTime):
            favoriteTime = itemTime
            favoriteItem = item
        else:
            if (itemTime < leastFavoriteTime):
                leastFavoriteTime = itemTime
                leastFavoriteItem = item

    if (leastFavoriteItem == favoriteItem):
        leastFavoriteItem = NULL_ITEM
    return (favoriteItem, leastFavoriteItem)



def GenerateItemUseStatDelta(eventList, playerItemUsage, playerItemTime, playerItemTimeInMatch, favoriteName, leastFavoriteName):
    delta = EmptyDelta()
    for event in eventList:
        actorID = event['actorID']
        typeID = event['typeID']
        dataLogDate = event['dataLogDate']
        currentMatch = event['matchID']
        if (playerItemUsage[actorID]['currentMatch'] != currentMatch):
            playerItemUsage[actorID]['currentMatch'] = currentMatch
            if (actorID in playerItemTimeInMatch):
                del playerItemTimeInMatch[actorID]
                playerItemUsage[actorID][(FAVO_ITEM + IN_MATCH_SUFFIX)] = NULL_ITEM
                playerItemUsage[actorID][(LEAST_FAVO_ITEM + IN_MATCH_SUFFIX)] = NULL_ITEM
        lastItem = playerItemUsage[actorID]['lastItem']
        if (lastItem != 0):
            useTime = int(round(((dataLogDate - playerItemUsage[actorID]['lastActionTime']) / 10000000.0)))
            playerItemTime[actorID][lastItem] += useTime
            playerItemTimeInMatch[actorID][lastItem] += useTime
        playerItemUsage[actorID]['lastItem'] = typeID
        playerItemUsage[actorID]['lastActionTime'] = dataLogDate

    for actorID in playerItemUsage:
        (favoriteItem, leastFavoriteItem,) = GetFavoriteAndLeastFavoriteItems(actorID, playerItemTime)
        if (playerItemUsage[actorID][FAVO_ITEM] != favoriteItem):
            playerItemUsage[actorID][FAVO_ITEM] = favoriteItem
            delta[actorID][favoriteName] = favoriteItem
        if (playerItemUsage[actorID][LEAST_FAVO_ITEM] != leastFavoriteItem):
            playerItemUsage[actorID][LEAST_FAVO_ITEM] = leastFavoriteItem
            delta[actorID][leastFavoriteName] = leastFavoriteItem

    for actorID in playerItemUsage:
        (favoriteItem, leastFavoriteItem,) = GetFavoriteAndLeastFavoriteItems(actorID, playerItemTimeInMatch)
        if (playerItemUsage[actorID][(FAVO_ITEM + IN_MATCH_SUFFIX)] != favoriteItem):
            playerItemUsage[actorID][(FAVO_ITEM + IN_MATCH_SUFFIX)] = favoriteItem
            delta[actorID][(favoriteName + IN_MATCH_SUFFIX)] = favoriteItem
        if (playerItemUsage[actorID][(LEAST_FAVO_ITEM + IN_MATCH_SUFFIX)] != leastFavoriteItem):
            playerItemUsage[actorID][(LEAST_FAVO_ITEM + IN_MATCH_SUFFIX)] = leastFavoriteItem
            delta[actorID][(leastFavoriteName + IN_MATCH_SUFFIX)] = leastFavoriteItem

    return delta



def GenerateWeaponUseStatDelta(callingProcess, eventList):
    return GenerateItemUseStatDelta(eventList, playerWeaponUsage, playerWeaponTime, playerWeaponTimeInMatch, STATNAME_FAVO_WEAPON, STATNAME_LEAST_FAVO_WEAPON)



def GenerateVehicleUseStatDelta(callingProcess, eventList):
    return GenerateItemUseStatDelta(eventList, playerVehicleUsage, playerVehicleTime, playerVehicleTimeInMatch, STATNAME_FAVO_VEHICLE, STATNAME_LEAST_FAVO_VEHICLE)



def GenerateObjectSpawnStatDelta(callingProcess, eventList):
    return EmptyDelta()



def GenerateTeamQuitStatDelta(callingProcess, eventList):
    return EmptyDelta()


if (__name__ == '__main__'):
    sqlFolder = os.path.abspath(('../../../../../db/db-eve/schemas/' + STATS_SCHEMA))
    print ('\n********* Generating .SQL to %s *********' % sqlFolder)
    fileNames = CreateAllStatsFiles(characterStats, sqlFolder)
    for fileName in fileNames:
        print ('touched %s' % fileName)

    print '********* Done *********'

